/*  -*- mode: c++; coding: utf-8; c-file-style: "stroustrup"; -*-

    Copyright 2008 Asier Aguirre <asier.aguirre@gmail.com>
    This file is part of Intromit.

    Intromit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Intromit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Intromit.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef METADATA_HH
#define METADATA_HH
//! \addtogroup intromit_core
//@{

// DEFINES
#include "util.hh"

#include <sys/types.h>
#include <regex.h>

// ENUMS
typedef enum metadata_marks_
{
    MD_MARK_PRIVATE_MEMBER=0,
    MD_MARK_STATUS_MEMBER,
    MD_MARK_PRIVATE_METHOD,
    MD_MARK_INTERFACE_METHOD,
    MD_MARK_ATTR_PREFIX,
    MD_MARK_ATTR_SEPARATOR,
    MD_MARK_ATTR_START,
    MD_MARK_ATTR_END,
    MD_MARK_ATTR_NOT,
    MD_MARK_ATTR_SELECTION,
    MD_MARK_ATTR_OFFLINE,
    MD_MARK_LAST
} metadata_marks;

typedef enum metadata_funcs_
{
    MD_FUNC_INIT=0,
    MD_FUNC_FINISH,
    MD_FUNC_TYPE_RECUR,
    MD_FUNC_NEXT,
    MD_FUNC_DOWN,
    MD_FUNC_UP,
    MD_FUNC_INIT_PASS,
    MD_FUNC_FINISH_PASS,
    MD_FUNC_LAST
} metadata_funcs;

// DECLARATIONS
class dwarf;
class source;
class config;
class string_index;
struct dwarf_base;
struct command_options;

// TYPEDEFS

//! Patterns for metadata matching extracted from config file
typedef struct _md_pattern_
{
    // info of the pattern
    int level;        // -1: typedef
    char *id;
    int n_components; // -1: pattern with no components;  0: component;  >0: pattern with n_components;  -2: redirect

    // attributes
    char *tag, *name, *encoding, *attr;
    int size, i_type;
    unsigned type_recur:1;
    unsigned reserved:31;

    // regex
    int regex_uses;
    regex_t regex_tag, regex_name, regex_encoding, regex_attr;
} metadata_pattern;

// CLASSES

//! Gets metadata bases from dwarf class and creates a product using a generator plug-in module
class metadata
{
    // ** CTOR/INIT VARIABLES **

    // utils
    dwarf *dw;
    source *src;
    config *cfg;

    // marks
    char *mark[MD_MARK_LAST];

    // extraction
    metadata_pattern *pattern;
    int n_pattern, max_pattern;
    int n_typedefs;

    // output files
    FILE **out;
    int n_out, max_out;

    // modules
    void **mod;
    int n_mod, max_mod;

    // prefix
    char *prefix;
    int n_prefix;

    // generic functions
    char *functions[MD_FUNC_LAST];

    // user data and pass info
    void *user_data;
    int pass, repetition;

    // options
    command_options *opts;

    // declarations gcc warning
    int gcc_need_to_find_decls;

    // ** STATUS VARIABLES **

    // ** PRIVATE FUNCTIONS **

    // selection
    bool selection_get_marks();
    bool selection();
    bool selection_rule(int add, char *file, char *name, char *tag, char *comment);
    bool selection_select_recur(int i_base, bool selected);
    bool selection_select_parents(int i_base, bool selected);

    // pattern match
    bool pattern_extract_from_cfg();
    bool pattern_check(int from=-1);
    bool pattern_check_restrictiveness(int more_restrictive, int less_restrictive);
    bool pattern_match_metadata(int i_base=-1, int i_pattern=-1);
    bool pattern_match_metadata_recur(int i_base, int i_pattern);
    bool pattern_match_type_recursion(int i_base, int i_pattern, int *i_deep_recur=NULL);
    bool pattern_from_config(int i_pattern, int i_cfg, int tag_pattern_allowed);
    bool pattern_precalculate(int i);
    bool pattern_match(int i_base, int i_pattern, int *ini_name=NULL, int *end_name=NULL);
    bool pattern_free(int i);
    bool pattern_match_select_class_children(int i_base);

    // unmatch impossible metadata
    bool pattern_unmatch_impossible_metadata(int verbo=0, char *filename=NULL);
    bool pattern_unmatch_recur(int i_base, int &counter, FILE *arch=stdout, int ref=-1);
    void pattern_unmatch_dump(dwarf_base *b, int &counter, FILE *arch, int ref);


    // generation
    bool generate_output(char *output_file=NULL, char *elf_name=NULL, char *modules_path=NULL, int verbo=0);
    bool generate_output_pass();
    bool generate_output_call_function(char *func_name_wo_prefix);

    // marks
    void set_mark(metadata_marks id, char *mark);

    // functions
    void set_function(metadata_funcs id, char *funcname);
    void reset_functions();

    // debug
    void dump_selection(const char *filename=NULL);
    void dump_selection_detailed(FILE *arch=NULL);
    void dump_patterns(char *filename=NULL);
    void dump_pattern(int i_pattern, FILE *arch=stdout);
    void dump_tree(const char *separator, const char *filename=NULL);

    // internal
    void ctor();
    void dtor();

public:
    metadata();
    ~metadata();

    //! Generate metadata output from file
    int generate(command_options *opts);

    // FUNCTIONS TO BE USED BY GENERATION LIBRARIES

    //! @name Tools
    //@{
    inline dwarf *get_dwarf() {return dw;}
    inline source *get_source() {return src;}
    string_index *get_doc(); //@}

    //! @name Out put files (opened and defined in config file)
    inline FILE *get_out(int index) {return out[index];}

    //! @name User data and pass info
    //@{
    inline void set_user_data(void *user_data) {this->user_data=user_data;}
    inline void *get_user_data() {return user_data;}
    inline int get_pass() {return pass;}
    inline int get_repetition() {return repetition;} //@}
};

//@}
#endif
